package com.wchen.gdoc.generate.mapping;

import com.alibaba.fastjson.JSONObject;
import com.wchen.gdoc.generate.config.ApplicationConfigProvide;
import com.wchen.gdoc.generate.mapping.data.MethodData;
import com.wchen.gdoc.generate.mapping.data.ParamData;
import com.wchen.gdoc.generate.mapping.resolver.AbsObjectStructureResolver;
import com.wchen.gdoc.generate.resource.structure.*;
import com.wchen.gdoc.generate.util.StructureUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * 默认方法结构解析器
 *
 * @author  wchen
 * @date    2019/11/11
 */
public class DefaultMethodStructureResolver extends AbsObjectStructureResolver {

    private final static Logger LOGGER = LoggerFactory.getLogger(DefaultMethodStructureResolver.class);
    public DefaultMethodStructureResolver() {
        super();
    }


    /**
     * 解析方法
     * @param classStructure
     * @param methodStructure
     * @return
     */
    public MethodData resolve(ClassStructure classStructure, MethodStructure methodStructure) {
        Assert.notNull(classStructure, "resolveMethod.paramClass can not be null");
        Assert.notNull(methodStructure, "resolveMethod.method can not be null");
        //入参
        if(ENABLE_DEBUG) {
            LOGGER.info(String.format("resolveMethodDataParameters begin.  class:%s, method:%s", classStructure.getClassName(), methodStructure.getMethodName()));
        }
        List<ParamData> paramDataList = createParamData(methodStructure.getParameterList());

        //出参
        if(ENABLE_DEBUG) {
            LOGGER.info(String.format("resolveMethodDataReturned begin.  class:%s, method:%s", classStructure.getClassName(), methodStructure.getMethodName()));
        }
        List<ParamData> returnDataList = null;
        if(Objects.nonNull(methodStructure.getReturned())){
            ParamData returnData = createReturnData(methodStructure.getReturned());
            if(returnData != null && returnData.getHasChild()) {
                returnDataList = (List<ParamData>) returnData.getParamValue();
            }
        }

        //结果拼装
        MethodData methodData = this.resolveMethodData(classStructure, methodStructure);
        methodData.setParamDataList(paramDataList);
        methodData.setReturnedData(returnDataList);
        return methodData;
    }


    /**
     * 解析并创建入参测试数据
     * @param parameterStructures
     * @return
     */
    private List<ParamData> createParamData(List<ParameterStructure> parameterStructures){
        List<ParamData> paramDataList = new ArrayList<>();
        int paramSize = parameterStructures.size();
        for (ParameterStructure parameterStructure : parameterStructures) {
            ParamData paramData = super.doResolverChain(parameterStructure);
            if(paramSize == 1 && paramData.getHasChild()) {
                paramDataList.addAll((List<ParamData>)paramData.getParamValue());
            }else {
                paramDataList.add(paramData);
            }
        }
        if(ENABLE_DEBUG) {
            LOGGER.info(String.format("createParamDataSuccess:", JSONObject.toJSONString(paramDataList, true)));
        }
        return paramDataList;
    }


    /**
     * 解析并创建出参测试数据
     * @param returnedStructure
     * @return
     */
    private ParamData createReturnData(ReturnedStructure returnedStructure){
        ParamData paramData = super.doResolverChain(returnedStructure);
        if(ENABLE_DEBUG) {
            LOGGER.info(String.format("createReturnDataSuccess:", JSONObject.toJSONString(paramData, true)));
        }
        return paramData;
    }


    /**
     * 解析方法数据
     * @param classStructure
     * @param methodStructure
     * @return
     */
    public MethodData resolveMethodData(ClassStructure classStructure, MethodStructure methodStructure) {
        MethodData methodData = new MethodData();
        String interfaceName = methodStructure.getCommentText();
        methodData.setMethodCommentText(interfaceName);
        methodData.setDescription(interfaceName);
        methodData.setContentType("JSON");

        String requestType = getRequestType(methodStructure);
        String mappingUrl = createMappingUrl(classStructure, methodStructure);
        methodData.setRequestMethod(requestType);
        methodData.setRequestUrl(mappingUrl);
        return methodData;
    }


    /**
     * 获取接口请求类型
     * @param methodStructure
     * @return
     */
    private String getRequestType(MethodStructure methodStructure){
        String annotationType = StructureUtil.getAssignAnnotationType(methodStructure.getMethodAnnotationList(), RequestMapping.class.getTypeName());
        if(annotationType.equals(PostMapping.class.getName())){
            return "POST";
        }else if(annotationType.equals(GetMapping.class.getName())){
            return "GET";
        }else if(annotationType.equals(PutMapping.class.getName())){
            return "PUT";
        }else if(annotationType.equals(DeleteMapping.class.getName())){
            return "DELETE";
        }else{
            return "POST";
        }
    }


    /**
     * 创建url映射
     * @param classStructure
     * @param methodStructure
     * @return
     */
    private String createMappingUrl(ClassStructure classStructure, MethodStructure methodStructure){
        String preUrl = ApplicationConfigProvide.getApplicationConfig().getDocumentConfig().getPreUrl();
        String methodUrl = StructureUtil.getAnnotationValue(methodStructure.getMethodAnnotationList(), RequestMapping.class.getTypeName(), "value");
        String classUrl = StructureUtil.getAnnotationValue(classStructure.getClassAnnotationList(), RequestMapping.class.getTypeName(), "value");
        if(Objects.isNull(methodUrl)){
            methodUrl = "";
        }
        return preUrl + classUrl + methodUrl;
    }

    /**
     * 参数解析
     *
     * @param objectStructure
     * @return
     */
    @Override
    public ParamData doResolve(ObjectStructure objectStructure) {
        return null;
    }

    /**
     * 判断是否支持解析器解析
     *
     * @param classType
     * @return
     */
    @Override
    public Boolean isSupport(String classType) {
        return null;
    }
}
